package com.ruoyi.common.utils.token;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.enums.ExceptionCode;
import com.ruoyi.common.exception.CustomException;
import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 杨光
 * @date 2021年08月12日 15:31
 */
public class JwtTokenUtils {

    private static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGwz5hYZrLbXV+8Zd2vTPGqxJ+d0g1HrtU/kFYNwNl0n6jpC+76rL3rXLlcUPPOjK2J2cZzrjOt26/Tni8xH0UDr0YVzmlzvZ9sB9ezoZJTWePmODVQro3nftRMOvMLbPEA7m9kpIbMwcvXg+eOrM6Nu2tnEDWch2NGa3OyAPKYQIDAQAB";
    private static final String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMbDPmFhmsttdX7xl3a9M8arEn53SDUeu1T+QVg3A2XSfqOkL7vqsvetcuVxQ886MrYnZxnOuM63br9OeLzEfRQOvRhXOaXO9n2wH17OhklNZ4+Y4NVCujed+1Ew68wts8QDub2SkhszBy9eD546szo27a2cQNZyHY0Zrc7IA8phAgMBAAECgYEArhQVsEhBwGTvgOyqkS4ICLmPiv+BWDTAMSI1rMMR0L3YeA22WMinUdCxTk4y6223OF2uKKYqqbFx508c44bbW4iRjQ59t36MwSMgFjsVXjtQHaFBq3lBiJAovRsd//lapPfas1a+RO0GjaKi3N37e4z/mkCwRzUf72n+vIGfoCECQQDmDUpzyqK9yduCxKZu0I0eZhnAQc9cli3HRHPFeVsHqx3w+7Q/VO302hHreoQbfWhn34KbROAqa+1/yGsuBSf1AkEA3S57NQgr4Cy7p1mgOwy+2QOB/USz+x3Ur07geJcnDTTIx4Ue00NVR524Z0vTNjIqFKeACd3JGh/f1etRmVoRPQJAfJJ13n274kmMNCOIfDkyMWPYTeNVBi3MXDsU9bnhMSXX8MZbtG+o6w2q5nhRURF3l8fQUYPaXx5SXP+KCkGAgQJAaHCkWPxMy4QT8AfQM1HnZE3VuaQRYIhLf6Q9NnQZSpEcJapkTdnDkReWlaAmUbcKS8p0GTSS2zUl2rtNQp5W+QJAUQZ2tztSgyiFJSs08RMZeGAKoIcDCegUsNVX7dYvxF7meYXPWIZgsqz+ZzxKEzBtn8yusPeSYImONXWOMWurGw==";
    //生成后台管理员jwttoken
    public static String generateJwtToken(Long userId,String userName,String userAccount){
        AccToken accToken = new AccToken(userId, userName, userAccount);
        accToken.setExpireDateTime(new Date((new Date()).getTime()+3600*24*300*1000));//超时时间设置为7天
        ObjectMapper mapper = new ObjectMapper();
        String ac = null;
        try {
            ac = mapper.writeValueAsString(accToken);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new CustomException(ExceptionCode.JSON_CONVERTION_EXCEPTION);
        }

        Map<String,Object> claims = new HashMap<>();
        claims.put(UserConstants.JWT_CLAIMS_KEY,ac);

        JwtBuilder builder = Jwts.builder();
        //使用对称加密生成jwt token
        builder.setClaims(claims).signWith(SignatureAlgorithm.HS512,UserConstants.JWT_SECRET_KEY);
        String jwtToken = builder.compact();

        return jwtToken;
    }

    //解析后台管理员jwtToken
    public static AccToken parseToken(String jwtToken){
        AccToken accToken = null;
        try {
            JwtParser parser = Jwts.parser();
            //如果解析失败，会抛出异常
            Jws<Claims> claimsJws = parser.setSigningKey(UserConstants.JWT_SECRET_KEY).parseClaimsJws(jwtToken);
            Claims claims = claimsJws.getBody();
            String acJson = (String)claims.get(UserConstants.JWT_CLAIMS_KEY);
            ObjectMapper mapper = new ObjectMapper();
            accToken = mapper.readValue(acJson, AccToken.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accToken;

    }


    //生成互联网用户的jwttoken
    public static String generateWebJwtToken(Long userId,String userName,String userAccount){
        AccToken accToken = new AccToken(userId, userName, userAccount);
        accToken.setExpireDateTime(new Date((new Date()).getTime()+3600*24*300*1000));//超时时间设置为7天
        ObjectMapper mapper = new ObjectMapper();
        String ac = null;
        try {
            ac = mapper.writeValueAsString(accToken);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new CustomException(ExceptionCode.JSON_CONVERTION_EXCEPTION);
        }

        Map<String,Object> claims = new HashMap<>();
        claims.put(UserConstants.JWT_CLAIMS_KEY,ac);

        JwtBuilder builder = Jwts.builder();
        //使用对称加密生成jwt token
        builder.setClaims(claims).signWith(SignatureAlgorithm.RS256, getRSAPrivateKey(privateKey));
        String jwtToken = builder.compact();

        return jwtToken;
    }

    //解析互联网用户登录的jwtToken
    public static AccToken parseWebToken(String jwtToken){
        AccToken accToken = null;
        try {
            JwtParser parser = Jwts.parser();
            //如果解析失败，会抛出异常
            Jws<Claims> claimsJws = parser.setSigningKey(getRSAPublicKey(publicKey)).parseClaimsJws(jwtToken);
            Claims claims = claimsJws.getBody();
            String acJson = (String)claims.get(UserConstants.JWT_CLAIMS_KEY);
            ObjectMapper mapper = new ObjectMapper();
            accToken = mapper.readValue(acJson, AccToken.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accToken;

    }

    public static Map<String, String> genRsaKey() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        System.out.println("=====================================================");
        System.out.println(Base64.encodeBase64String(publicKeyBytes));
        System.out.println("=====================================================");
        System.out.println(Base64.encodeBase64String(privateKeyBytes));
        System.out.println("=====================================================");
        HashMap<String, String> keyMap = new HashMap<>();
        keyMap.put("publicKey", Base64.encodeBase64String(publicKeyBytes));
        keyMap.put("privateKey", Base64.encodeBase64String(privateKeyBytes));
        return keyMap;
    }

    /**
     * 获取 RSAPrivateKey
     *
     * @param priKey base64加密私钥
     */
    private static RSAPrivateKey getRSAPrivateKey(String priKey)  {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKey));
        RSAPrivateKey privateKey = null;

        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return privateKey;
    }


    /**
     * 获取 RSAPublicKey
     *
     * @param pubKey base64加密公钥
     */
    private static RSAPublicKey getRSAPublicKey(String pubKey)  {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubKey));
        RSAPublicKey publicKey = null;

        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publicKey;
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {


        try {
            Map<String, String> keys = genRsaKey();


        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }


//        String token = generateJwtToken(1L, "zhangsan", "zhangsan");
//
//        AccToken accToken = parseToken(token);


//        System.out.println(accToken);

    }
}
